﻿/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Cobalt.Framework.UI
{

	public abstract class Element
	{

		public Property<Vector2> Origin;
		public Property<float> Opacity;
		public Property<bool> Visible;

		protected Element( UiContext context )
		{
			Opacity.SetSimpleValue( 1.0F );
			Visible.SetSimpleValue( true );

			UiContext = context;
		}

		public UiContext UiContext { get; private set; }

		/// <summary>
		/// Gets the meta-object associated with this element during active traversal.
		/// </summary>
		/// <returns>
		/// The tag associated with this element during the current traversal,
		/// or <c>null</c> if the element is not part of the active traversal.
		/// </returns>
		public object GetRoutingMeta()
		{
			return UiContext.GetRoutingMeta( this );
		}

		public bool IsFocused()
		{
			return UiContext.IsFocusedElement( this );
		}

		public bool ContainsFocus()
		{
			return UiContext.IsOrContainsFocusedElement( this );
		}

		protected internal virtual void OnPreviewEvent( IEventRoutingContext context )
		{
		}

		protected internal virtual void OnHandleEvent( IEventRoutingContext context )
		{
		}

		protected internal virtual void Render( IRenderContext context )
		{
		}

		protected internal virtual void TraverseToRender( ITraversalContext context )
		{
		}

		protected internal virtual void OnRootStateChanged( RootState state )
		{
		}

	}

	public struct RootState
	{
		public bool IsVisible { get; set; }
		public bool IsTopmost { get; set; }
	}

	public struct Property<T>
	{
		private T value;
		private Func<T> dynamicValue;

		public T Evaluate()
		{
			if( dynamicValue != null )
				return dynamicValue();
		
			return value;
		}

		public void SetSimpleValue( T value )
		{
			this.dynamicValue = null;
			this.value = value;
		}

		public void SetDynamicValue( Func<T> value )
		{
			this.value = default( T );
			this.dynamicValue = value;
		}
	}

	public abstract class Event
	{
		/// <summary>
		/// Called when descending another level in the route.
		/// </summary>
		/// <param name="route">The route to descend into</param>
		/// <remarks>
		/// Events that mutate based on the current element should
		/// adjust themselves by the value of <paramref name="route"/>.<see cref="RoutingPath.Top">Top</see>
		/// </remarks>
		public virtual void RouteInto( IRoute route )
		{
		}

		public virtual void RoutOutOf( IRoute route )
		{
		}
	}
}